// encoding utf-8

#include <QLabel>
#include <QLayout>
#include <QFile>
#include <QFileInfo>
#include <QDir>
#include <QSettings>
#include <QDebug>
#include <QMessageBox>
#include <QInputDialog>
#include <QFont>
#include <QyTabWidget>
#include <QyLexerFactory>
#include <QyFileDialog>
#include <QySciLexer>

#include "QyEditorBase.h"
#include "QyFindDialog.h"
#include "QyReplaceDialog.h"
#include "QyGotoDialog.h"
#include "QyCodecDialog.h"

/**************************************************************************************************/
QMap<QString,QVariant> QyEditorBase::p_sciEditConfig;
/**************************************************************************************************/

class QyTabPagePrivate : public QWidget {
public:
	QyTabPagePrivate( QWidget * parent=0 );

	QLabel * fileNameLine;
	QySciEdit * edit;
	QString title;

};

QyTabPagePrivate::QyTabPagePrivate( QWidget * parent ) : QWidget(parent) {

	QVBoxLayout * lo = new QVBoxLayout(this);
	fileNameLine = new QLabel(this);
	edit = new QySciEdit(this);

	fileNameLine->setAlignment(Qt::AlignHCenter|Qt::AlignVCenter);

	lo->setSpacing(0);
	lo->setMargin(0);
	lo->addWidget(fileNameLine);
	lo->addWidget(edit);

	setFocusPolicy(Qt::NoFocus);

	connect( edit, SIGNAL( fileNameChanged(const QString&) ),
		fileNameLine, SLOT( setText(const QString&) ) );

}

/**************************************************************************************************/

QyEditorBase::QyEditorBase( QWidget * parent ) : QWidget(parent) {

	p_statusPattern = tr(
		"line: ${LINE}/${TOTALLINES} | "
		"col: ${COL}/${LINELENGTH} | "
		"sel: ${SELSYMCOUNT} in ${SELLINESCOUNT} | "
		"size: ${FILESIZE}b | "
		"codec: ${ENCODING} | "
		"lexer: ${LEXERNAME}"
	);
	p_fileFilter = tr("All files (*)");

	QVBoxLayout * lo = new QVBoxLayout(this);
	tabWidget = new QyTabWidget(this);
	findDialog = new QyFindDialog(this);
	replaceDialog = new QyReplaceDialog(this);
	gotoDialog = new QyGotoDialog(this);
	codecDialog = new QyCodecDialog(this);

	lo->setMargin(0);
	lo->setSpacing(0);
	lo->addWidget(tabWidget);

	connect( tabWidget, SIGNAL( tabChanged(const QString&,QWidget*) ),
		this, SLOT( currentTabChanged(const QString&,QWidget*) ) );
	connect( findDialog, SIGNAL( initFind(const QString&,bool,bool,bool) ),
		this, SLOT( findText(const QString&,bool,bool,bool) ) );
	connect( replaceDialog, SIGNAL( replaceOne( const QString&,const QString&,bool,bool,bool) ),
		this, SLOT( replaceOne( const QString&,const QString&,bool,bool,bool) ) );
	connect( replaceDialog, SIGNAL( replaceAll( const QString&,const QString&,bool,bool,bool) ),
		this, SLOT( replaceAll( const QString&,const QString&,bool,bool,bool) ) );
	connect( replaceDialog, SIGNAL( replaceInSelection( const QString&,const QString&,bool,bool,bool) ),
		this, SLOT( replaceInSelection( const QString&,const QString&,bool,bool,bool) ) );
	connect( gotoDialog, SIGNAL( initGoto(int) ),
		this, SLOT( gotoLine(int) ) );
	connect( codecDialog, SIGNAL( codecChanged(const QString&) ),
		this, SLOT( reopenCurrentWithCodec(const QString&) ) );

	checkEmpty();

}

void QyEditorBase::openEmpty( const QString & section ) {

	createPage( validateSectionName(section), tr("Empty"), false );

}

void QyEditorBase::openFile( QString fileName, const QString & section ) {

	openFileOnLine( fileName, 0, section );

}

void QyEditorBase::openFileOnLine( QString fileName, int line, const QString & section ) {

	if ( QFileInfo(fileName).isDir() )
		return;

	if ( fileName.isEmpty() ) {

		QString currentDir;

		if ( QySciEdit * edit = currentEdit() )
			currentDir = QFileInfo( edit->fileName() ).absolutePath();
		else
			currentDir = QDir::currentPath();

		fileName = QyFileDialog::getOpenFileName( this, tr("Open file"), currentDir,
			fileDialogFilter() );

		if ( fileName.isEmpty() )
			return;

	}

	QFileInfo info(fileName);
	QString fullFileName( info.absoluteFilePath() );
	QyTabPagePrivate * tabPage = page( validateSectionName(section), fileName );

	if (tabPage) {

		tabWidget->setCurrentWidget(tabPage);

	} else {

		tabPage = createPage( validateSectionName(section), info.fileName() );

		tabPage->edit->openFile( fullFileName, line );
		tabPage->edit->setLexer( QyLexerFactory::lexer(fileName) );
		tabPage->edit->foldAll(false);
		tabPage->edit->ensureLineVisible(line);

	}

}

void QyEditorBase::saveCurrent() {

	QySciEdit * edit = currentEdit();

	if (!edit)
		return;

	if ( edit->fileName().isEmpty() )
		saveCurrentAs();
	else {

		if ( edit->save() )
			emit fileSaved( edit->fileName() );

	}

}

void QyEditorBase::saveCurrentAs() {

	QySciEdit * edit = currentEdit();

	if (!edit)
		return;

	QString currentPath, fileName( edit->fileName() ), selectedFilter;

	currentPath = ( fileName.isEmpty() ? QDir::currentPath() : QFileInfo(fileName).absolutePath() );
	fileName = QyFileDialog::getSaveFileName( this, tr("Save as ..."), currentPath,
		fileDialogFilter(), &selectedFilter );

	if ( fileName.isEmpty() )
		return;

	fileName = validateFileName( fileName, selectedFilter );

#ifdef QY_EDITORBASE_INTERNALOVERWRITEREQUEST

	if ( QFile::exists(fileName) ) {

		if ( QMessageBox::question( this, tr("Save file"), tr("File already exists. Overwrite?"),
			QMessageBox::Yes|QMessageBox::No, QMessageBox::Yes ) == QMessageBox::No )
		{
			return;
		}

	}

#endif/*QY_EDITORBASE_INTERNALOVERWRITEREQUEST*/

	if ( QsciLexer * lexer = QyLexerFactory::lexer(fileName) ) {

		if ( edit->lexer() != lexer )
			edit->setLexer(lexer);

	}

	if ( !edit->save(fileName) )
		qWarning( "Can't save \"%s\" file", fileName.toStdString().c_str() );
	else if ( QyTabPagePrivate * tabPage = currentPage() ) {

		tabPage->title = QFileInfo(fileName).fileName();
		tabWidget->setWidgetTitle( tabPage, tabPage->title );
		emit fileSaved( edit->fileName() );

	}

}

void QyEditorBase::closeCurrent() {

	tabWidget->removeTab( currentPage() );
	checkEmpty();

}

void QyEditorBase::closeCurrentSection() {

	tabWidget->removeTabLine();
	checkEmpty();

}

void QyEditorBase::clear() {

	tabWidget->clear();
	checkEmpty();

}

void QyEditorBase::updateStatus() {

	QyTabPagePrivate * tabPage = currentPage();

	if (!tabPage)
		return;

	QString statusStr(p_statusPattern),
		lexerName("default");
	QFileInfo info( tabPage->edit->fileName() );
	int lineFrom, indexFrom, lineTo, indexTo, selLength;

	if ( QsciLexer * lexer = tabPage->edit->lexer() )
		lexerName = lexer->language();

	tabPage->edit->getSelection( &lineFrom, &indexFrom, &lineTo, &indexTo );
	selLength = abs( tabPage->edit->positionFromLineIndex( lineFrom, indexFrom ) -
		tabPage->edit->positionFromLineIndex( lineTo, indexTo ) );

	statusStr.replace( "${FILENAME}", info.fileName() );
	statusStr.replace( "${FILEPATH}", info.absoluteFilePath() );
	statusStr.replace( "${TOTALLINES}", QString::number( tabPage->edit->lines() ) );
	statusStr.replace( "${LINE}", QString::number( tabPage->edit->line() + 1 ) );
	statusStr.replace( "${COL}", QString::number( tabPage->edit->index() + 1 ) );
	statusStr.replace( "${LINELENGTH}", QString::number( tabPage->edit->trueLineLength( tabPage->edit->line() ) ) );
	statusStr.replace( "${SELLINESCOUNT}", QString::number( abs( lineTo - lineFrom ) + 1 ) );
	statusStr.replace( "${SELSYMCOUNT}", QString::number(selLength) );
	statusStr.replace( "${LEXERNAME}", lexerName );
	statusStr.replace( "${FILESIZE}", QString::number( info.size() ) );
	statusStr.replace( "${ENCODING}", tabPage->edit->encodingName() );

	// bool restoreSignalBlocking = signalsBlocked();
	// if (restoreSignalBlocking)
		// blockSignals(false);

	emit statusChanged(statusStr);

	// if (restoreSignalBlocking)
		// blockSignals(true);

}

void QyEditorBase::loadSession( QString fileName ) {

	if ( fileName.isEmpty() ) {

		QString currentDir;

		if ( QySciEdit * edit = currentEdit() )
			currentDir = QFileInfo( edit->fileName() ).absolutePath();
		else
			currentDir = QDir::currentPath();

		fileName = QyFileDialog::getOpenFileName( this, tr("Open session"), currentDir,
			tr("All(*)") );

		if ( fileName.isEmpty() )
			return;

	}

	tabWidget->clear();

	QString prefix;
	QSettings settings( fileName, QSettings::IniFormat );
	QStringList secNames( settings.value( prefix + "/sections/names" ).toStringList() );

	// qDebug() << "restore secNames" << secNames;

	foreach ( QString name, secNames ) {

		QStringList files( settings.value( prefix + "/sections/" + name ).toStringList() );

		// qDebug() << "restore files" << files;

		foreach ( QString file, files ) {

			QStringList components( file.split(":") );

			if ( components.count() < 2 ) {

				qWarning( "Config parsing error on: %s [%s]",
					file.toStdString().c_str(),
					name.toStdString().c_str()
				);

				continue;
			}

			QString fileName( components.takeFirst() );

			if ( QFile::exists(fileName) ) {

				// qDebug() << "open" << fileName << "on" << name;
				openFileOnLine( fileName, components.takeFirst().toInt(), name );

				if ( QyTabPagePrivate * tabPage = QyEditorBase::currentPage() ) {

					foreach ( QString bmIndex, components )
						tabPage->edit->addMarker( bmIndex.toInt(), QySciMarkerType::Bookmark );

				}

			} else {

				// qDebug() << "open \"Empty\" on" << name;

				openEmpty();

			}

		}

	}

	QString currentSection( settings.value( prefix + "/sections/current").toString() );

	// qDebug() << "restore currentSection" << currentSection;

	if ( !currentSection.isEmpty() ) {

		tabWidget->setCurrentTabLine(currentSection);
		tabWidget->setCurrentIndex( settings.value( prefix + "/sections/index").toInt() );

		// qDebug() << "restore index" << settings.value( prefix + "/sections/index").toInt();

	}

	checkEmpty();

}

void QyEditorBase::saveSession( QString fileName ) {

	if ( fileName.isEmpty() ) {

		fileName = QyFileDialog::getSaveFileName( this, tr("Save session"), QDir::currentPath(),
			tr("All(*)") );

		if ( fileName.isEmpty() )
			return;

	}

	QFile::remove(fileName);

	QString prefix;
	QSettings settings( fileName, QSettings::IniFormat );
	QStringList secNames( tabWidget->tabLineNames() );

	if ( secNames.isEmpty() || tabWidget->currentTabLine().isEmpty() )
		return;

	settings.setValue( prefix + "/sections/names", secNames );
	settings.setValue( prefix + "/sections/current", tabWidget->currentTabLine() );
	settings.setValue( prefix + "/sections/index", tabWidget->currentIndex() );

	foreach ( QString name, secNames ) {

		QList<QWidget*> tabPages = tabWidget->widgetsOnLine(name);
		QStringList files;
		QyTabPagePrivate * tabPage = 0;

		// qDebug() << "save section" << name;
		// qDebug() << "page count" << tabPages.count();

		foreach ( QWidget * w, tabPages ) {

			tabPage = dynamic_cast<QyTabPagePrivate *>(w);

			if (tabPage) {

				QString str = QString("%1:%2")
					.arg( tabPage->edit->fileName() )
					.arg( tabPage->edit->line() + 1 );

				int line = 0;

				do {

					if (line)
						line += 1;

					line = tabPage->edit->markerFindNext( line, 1 << QySciMarkerType::Bookmark );

					// qDebug() << "line" << line;

					if ( line >= 0 )
						str += QString(":%1").arg(line);

				} while ( line >= 0 );

				// qDebug() << "edit str" << str;

				files.append(str);

			}

		}

		// qDebug() << "section files" << files;

		settings.setValue( prefix + "/sections/" + name, files );

	}

}

void QyEditorBase::switchCurrentFile() {

	QyTabPagePrivate * tabPage = currentPage();

	if (!tabPage)
		return;

	QString fileName( tabPage->edit->fileName() );
	QFileInfo info(fileName);
	QDir dir( info.absolutePath() );
	QStringList files( dir.entryList( QStringList() << info.completeBaseName() + ".*" ) );

	files.removeAll( info.fileName() );

	if ( files.isEmpty() )
		return;

	bool ok;

	if ( files.count() > 1 )
		fileName = QInputDialog::getItem( this, tr("Select file"), tr("Files"), files, 0, false, &ok );
	else {

		ok = true;
		fileName = files.first();

	}

	if ( fileName.isEmpty() || !ok )
		return;

	fileName = info.absolutePath() + "/" + fileName;

	// запись позиции курсора
	while ( p_switchFileStack.count() > 5 ) {

// 		qDebug() << "remove" <<
		p_switchFileStack.takeFirst().fileName;

	}

	int pos = -1, index;
	if ( ( index = p_switchFileStack.indexOf( QyFileInfoRecord(fileName) ) ) >= 0 )
		pos = p_switchFileStack[index].pos;

// 	qDebug() << "pos" << pos << fileName;

	QyFileInfoRecord newRec( tabPage->edit->fileName(), tabPage->edit->line() );

	if ( ( index = p_switchFileStack.indexOf(newRec) ) >= 0 )
		p_switchFileStack.takeAt(index);

	p_switchFileStack.append(newRec);

	tabPage->title = QFileInfo(fileName).fileName();
	tabPage->edit->openFile(fileName);
	tabPage->edit->foldAll(false);
	tabWidget->setWidgetTitle( tabPage, tabPage->title );

	if ( pos >= 0 ) {

		tabPage->edit->setLine(pos);
		tabPage->edit->ensureLineVisible(pos);

	}

}

void QyEditorBase::toggleBookmark() {

	QyTabPagePrivate * tabPage = QyEditorBase::currentPage();

	if (!tabPage)
		return;

	int line = tabPage->edit->line();

	if ( tabPage->edit->markersAtLine(line) )
		tabPage->edit->removeMarkers( line, QySciMarkerType::Bookmark );
	else
		tabPage->edit->addMarker( line, QySciMarkerType::Bookmark );

}

inline int findNextBookmarkOn( QySciEdit * edit, int line, int mask ) {

	int result = edit->markerFindNext( line, mask );

	if ( result < 0 )
		result = edit->markerFindNext( 0, mask );
	else if ( line == result ) {

		result = edit->markerFindNext( line + 1, mask );

		if ( result < 0 )
			result = edit->markerFindNext( 0, mask );

	}

	return result;
}

void QyEditorBase::findNextBookmark() {

	QyTabPagePrivate * tabPage = QyEditorBase::currentPage();

	if (!tabPage)
		return;

	int line = findNextBookmarkOn( tabPage->edit, tabPage->edit->line(), 1 << QySciMarkerType::Bookmark );

	if ( line >= 0 )
		tabPage->edit->setLine(line);

}

void QyEditorBase::updateConfig() {

	QStringList sectionsNames( tabWidget->tabLineNames() );
	QList<QWidget*> widgets;
	QyTabPagePrivate * tabPage = 0;

	foreach ( QString sectionName, sectionsNames ) {

		widgets = tabWidget->widgetsOnLine(sectionName);

		foreach ( QWidget * widget, widgets ) {

			tabPage = dynamic_cast<QyTabPagePrivate *>(widget);

			if (tabPage) {

				tabPage->edit->setLexer( QyLexerFactory::lexer( tabPage->edit->fileName() ) );
				applySciEditSettings(tabPage->edit);

			}

		}

	}

}

void QyEditorBase::findText( const QString & text, bool re, bool cs, bool wm ) {

	QySciEdit * edit = currentEdit();

	if (!edit)
		return;

	if ( text.isEmpty() ) {

		if ( edit->hasSelectedText() )
			findDialog->setText( edit->selectedText() );

		findDialog->show();

	} else {

		lastRequest = QySciFindRequest( text, re, cs, wm );

		edit->findText(lastRequest);

	}

}

void QyEditorBase::findTextNext() {

	QySciEdit * edit = currentEdit();

	if (!edit)
		return;

	edit->findText(lastRequest);

}

void QyEditorBase::replaceText() {

	QySciEdit * edit = currentEdit();

	if (!edit)
		return;

	if ( edit->hasSelectedText() )
		replaceDialog->setFindText( edit->selectedText() );

	replaceDialog->show();

}

void QyEditorBase::toggleCurrentComment() {

	QySciEdit * edit = currentEdit();

	if (!edit)
		return;

	edit->toggleCommentSelectedLines();

}

void QyEditorBase::toggleCurrentFoldAll() {

	QySciEdit * edit = currentEdit();

	if (!edit)
		return;

	edit->foldAll(false);

}

void QyEditorBase::toggleCurrentFoldCurrent() {

	QySciEdit * edit = currentEdit();

	if (!edit)
		return;

	edit->foldCurrent();

}

void QyEditorBase::gotoLine( int line ) {

	QySciEdit * edit = currentEdit();

	if (!edit)
		return;

	if ( line < 0 ) {

		gotoDialog->setMaximum( edit->lines() );
		gotoDialog->show();

	} else {

		edit->setLine( line - 1 );
		edit->ensureLineVisible( line - 1 );

	}

}

void QyEditorBase::reopenCurrentWithCodec( const QString & codecName ) {

	QySciEdit * edit = currentEdit();

	if (!edit)
		return;

	qDebug() << "codecName" << codecName;

	if ( codecName.isEmpty() )
		codecDialog->exec();
	else {

		qDebug() << "edit->fileName()" << edit->fileName();

		edit->openFile( edit->fileName(), codecName );
		edit->foldAll(false);

		updateStatus();

	}

}

void QyEditorBase::setSciEditConfig( QMap<QString,QVariant> sciEditConfig ) {

	p_sciEditConfig = sciEditConfig;

}

void QyEditorBase::currentTabChanged( const QString & section, QWidget * widget ) {

	Q_UNUSED(section);

	if ( QyTabPagePrivate * tabPage = dynamic_cast<QyTabPagePrivate *>(widget) )
		tabPage->edit->setFocus();

	updateStatus();

}

void QyEditorBase::editorModificationChanged( bool m ) {

	if ( QyTabPagePrivate * tabPage = currentPage() )
		tabWidget->setWidgetTitle( tabPage, m ? tabPage->title + "*" : tabPage->title );

}

void QyEditorBase::encodingChanged( const QString & ) {

	updateStatus();

}

void QyEditorBase::fileNameChanged( const QString & ) {

	updateStatus();

}

void QyEditorBase::linesChanged() {

	updateStatus();

}

void QyEditorBase::cursorPositionChanged( int, int ) {

	updateStatus();

}

void QyEditorBase::editMarginClicked( int margin, int line, Qt::KeyboardModifiers state ) {

	Q_UNUSED(margin);
	Q_UNUSED(line);
	Q_UNUSED(state);

	// addMarker();

}

void QyEditorBase::replaceOne( const QString & findText, const QString & replaceText, bool re,
	bool cs, bool wm )
{

	QySciEdit * edit = currentEdit();

	if (!edit)
		return;

	edit->replaceOne( findText, replaceText, re, cs, wm );

}

void QyEditorBase::replaceAll( const QString & findText, const QString & replaceText, bool re,
	bool cs, bool wm )
{

	QySciEdit * edit = currentEdit();

	if (!edit)
		return;

	edit->replaceAll( findText, replaceText, re, cs, wm );

}

void QyEditorBase::replaceInSelection( const QString & findText, const QString & replaceText,
	bool re, bool cs, bool wm )
{

	QySciEdit * edit = currentEdit();

	if (!edit)
		return;

	edit->replaceInSelection( findText, replaceText, re, cs, wm );

}

QyTabPagePrivate * QyEditorBase::createPage( const QString & section, const QString & title,
	bool checkEmpty )
{

	if (checkEmpty) {

		if ( tabWidget->count() == 1 && section == tabWidget->currentTabLine() ) {

			QyTabPagePrivate * currentTabPage = currentPage();

			if ( currentTabPage->edit->fileName().isEmpty() ) {

				currentTabPage->title = title;
				tabWidget->setWidgetTitle( currentTabPage, title );

				return currentTabPage;
			}

		}

	}

	QyTabPagePrivate * page = new QyTabPagePrivate;

	applySciEditSettings(page->edit);

	tabWidget->addTab( validateSectionName(section), title, page );
	page->title = title;

	connect( page->edit, SIGNAL( modificationChanged(bool) ),
		this, SLOT( editorModificationChanged(bool) ) );
	connect( page->edit, SIGNAL( encodingChanged(const QString&) ),
		this, SLOT( encodingChanged(const QString&) ) );
	connect( page->edit, SIGNAL( fileNameChanged(const QString&) ),
		this, SLOT( fileNameChanged(const QString&) ) );
	connect( page->edit, SIGNAL( linesChanged() ),
		this, SLOT( linesChanged() ) );
	connect( page->edit, SIGNAL( cursorPositionChanged(int,int) ),
		this, SLOT( cursorPositionChanged(int,int) ) );
	connect( page->edit, SIGNAL( marginClicked(int,int,Qt::KeyboardModifiers) ),
		this, SLOT( editMarginClicked(int,int,Qt::KeyboardModifiers) ) );

	return page;
}

QyTabPagePrivate * QyEditorBase::currentPage() const {

	return dynamic_cast<QyTabPagePrivate*>( tabWidget->currentWidget() );
}

QyTabPagePrivate * QyEditorBase::page( const QString & section, const QString & fileName ) const {


	QStringList sectionsNames( tabWidget->tabLineNames() );

	if ( !sectionsNames.contains(section)  )
		return 0;


	QList<QWidget*> tabPages = tabWidget->widgetsOnLine(section);
	QyTabPagePrivate * tabPage = 0;

	foreach ( QWidget * w, tabPages ) {

		tabPage = dynamic_cast<QyTabPagePrivate *>(w);

		if (tabPage) {

			if ( tabPage->edit->fileName() == fileName )
				return tabPage;

		}

	}

	return 0;
}

QySciEdit * QyEditorBase::currentEdit() const {

	if ( QyTabPagePrivate * tabPage = currentPage() )
		return tabPage->edit;

	return 0;
}

QString QyEditorBase::validateSectionName( const QString & name ) {

	QString currentName( tabWidget->currentTabLine() );

	return name.isEmpty() ? ( currentName.isEmpty() ? tr("default") : currentName ) : name;
}

void QyEditorBase::checkEmpty() {

	// qDebug() << "tabWidget->count()" << tabWidget->count();

	if ( !tabWidget->count() ) {

		// qDebug() << "openEmpty";
		openEmpty();

		// qDebug() << "tabWidget->count()" << tabWidget->count();

	}

}

QString QyEditorBase::fileDialogFilter() {

	QList<QyLexerFactory*> factories( QyLexerFactory::factories() );
	QStringList filterList;

	filterList.append(p_fileFilter);

	foreach( QyLexerFactory * factory, factories )
		filterList.append( QString("%1 (%2)").arg( factory->displayName() )
			.arg( factory->fileFilter() ) );

	return filterList.join(";;");
}

QString QyEditorBase::validateFileName( const QString & fileName, const QString & filter ) {

	QString result(fileName),
		mask( filter.section( '(', 1 ).remove(")") );

	if ( mask == "*.*" || mask == "*" || QDir::match( mask, fileName ) )
		return fileName;

	qDebug() << "mask" << mask;

	if ( mask.count() ) {

		QStringList masks( mask.split(",") );

		if ( masks.count() > 1 )
			mask = QInputDialog::getItem( this, tr("Select file mask"), tr("Masks"), masks, 0, false );

		if ( mask.isEmpty() )
			mask = masks.first();

		result += "." + mask.section( '.', -1 );

	}

	return result;
}

#define __TESTANDSETCOLOR( name, func ) if ( p_sciEditConfig.contains(name) ) edit->func( QColor( p_sciEditConfig[name].toString() ) )
#define __TESTANDSETINT( name, func ) if ( p_sciEditConfig.contains(name) ) edit->func( p_sciEditConfig[name].toInt() )
#define __TESTANDSETCOLORARGS( name, func, args ) if ( p_sciEditConfig.contains(name) ) edit->func( QColor( p_sciEditConfig[name].toString() ), args )

void QyEditorBase::applySciEditSettings( QySciEdit * edit ) {

	Q_ASSERT(edit);
	edit->resetSelectionBackgroundColor();
	edit->resetSelectionForegroundColor();
	edit->resetFoldMarginColors();

	__TESTANDSETCOLORARGS( "markers.arrow.back", setMarkerBackgroundColor, QySciMarkerType::Arrow );
	__TESTANDSETCOLORARGS( "markers.arrow.fore", setMarkerForegroundColor, QySciMarkerType::Arrow );
	__TESTANDSETCOLORARGS( "markers.error.back", setMarkerBackgroundColor, QySciMarkerType::Error );
	__TESTANDSETCOLORARGS( "markers.error.fore", setMarkerForegroundColor, QySciMarkerType::Error );
	__TESTANDSETCOLORARGS( "markers.warning.back", setMarkerBackgroundColor, QySciMarkerType::Warning );
	__TESTANDSETCOLORARGS( "markers.warning.fore", setMarkerForegroundColor, QySciMarkerType::Warning );
	__TESTANDSETCOLORARGS( "markers.bookmark.back", setMarkerBackgroundColor, QySciMarkerType::Bookmark );
	__TESTANDSETCOLORARGS( "markers.bookmark.fore", setMarkerForegroundColor, QySciMarkerType::Bookmark );

	__TESTANDSETCOLOR( "caret.fore", setCaretForegroundColor );
	__TESTANDSETCOLOR( "caret.back", setCaretLineBackgroundColor );
	__TESTANDSETCOLOR( "selection.fore", setSelectionForegroundColor );
	__TESTANDSETCOLOR( "selection.back", setSelectionBackgroundColor );
	__TESTANDSETCOLOR( "fore", setColor );
	__TESTANDSETCOLOR( "back", setPaper );
	__TESTANDSETCOLOR( "calltipsbackgroundcolor", setCallTipsBackgroundColor );
	__TESTANDSETCOLOR( "calltipsforegroundcolor", setCallTipsForegroundColor );
	__TESTANDSETCOLOR( "calltipshighlightcolor", setCallTipsHighlightColor );
	__TESTANDSETCOLOR( "marginsbackgroundcolor", setMarginsBackgroundColor );
	__TESTANDSETCOLOR( "marginsforegroundcolor", setMarginsForegroundColor );

	if ( p_sciEditConfig.contains("foldmargincolors.back") &&
		p_sciEditConfig.contains("foldmargincolors.fore") )
	{

		edit->setFoldMarginColors( QColor( p_sciEditConfig["foldmargincolors.fore"].toString() ),
			QColor( p_sciEditConfig["foldmargincolors.back"].toString() ) );

	}

	__TESTANDSETCOLOR( "indentationguidesbackgroundcolor", setIndentationGuidesBackgroundColor );
	__TESTANDSETCOLOR( "indentationguidesforegroundcolor", setIndentationGuidesForegroundColor );
	__TESTANDSETCOLOR( "matchedbracebackgroundcolor", setMatchedBraceBackgroundColor );
	__TESTANDSETCOLOR( "matchedbraceforegroundcolor", setMatchedBraceForegroundColor );
	__TESTANDSETCOLOR( "unmatchedbracebackgroundcolor", setUnmatchedBraceBackgroundColor );
	__TESTANDSETCOLOR( "unmatchedbraceforegroundcolor", setUnmatchedBraceForegroundColor );
	__TESTANDSETCOLOR( "edgecolor", setEdgeColor );

	__TESTANDSETINT( "indentationwidth", setIndentationWidth );
	__TESTANDSETINT( "tabwidth", setTabWidth );
	__TESTANDSETINT( "edgecolumn", setEdgeColumn );
	__TESTANDSETINT( "autocompletionthreshold", setAutoCompletionThreshold );
	__TESTANDSETINT( "caretwidth", setCaretWidth );

	if ( p_sciEditConfig.contains("caretlinevisible") )
		edit->setCaretLineVisible( p_sciEditConfig["caretlinevisible"].toBool() );

	if ( p_sciEditConfig.contains("setautostriptrailingspaces") )
		edit->setAutoStripTrailingSpaces( p_sciEditConfig["setautostriptrailingspaces"].toBool() );

	if ( p_sciEditConfig.contains("setwhitespacevisibility") ) {

		switch ( p_sciEditConfig["setwhitespacevisibility"].toInt() ) {

		default:
			qWarning("Unknow value for setwhitespacevisibility");
		case 0:
			edit->setWhitespaceVisibility(QsciScintilla::WsInvisible);
			break;

		case 1:
			edit->setWhitespaceVisibility(QsciScintilla::WsVisible);
			break;

		case 2:
			edit->setWhitespaceVisibility(QsciScintilla::WsVisibleAfterIndent);
			break;

		}

	}

	if ( p_sciEditConfig.contains("font") ) {

		QFont font;

		font.fromString( p_sciEditConfig["font"].toString() );
		edit->setFont(font);

	}

}

#undef __TESTANDSETCOLOR
#undef __TESTANDSETINT
#undef __TESTANDSETCOLORARGS
